'use client'; import { useRef, useState } from 'react'; import { useRouter } from 'next/navigation'; import { ImageIcon, Camera, Trash2, User } from 'lucide-react'; import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog'; import { fetchApi } from '@/lib/utils/client'; import { useMemberContext } from '@/contexts/memberProvider'; import { UserProfileDto } from '@/types/account/profile'; type Props = { open: boolean; onOpenChange: (open: boolean) => void; profile: UserProfileDto; }; export default function UserProfileEditDialog({ open, onOpenChange, profile }: Props) { const router = useRouter(); const { member, setMember } = useMemberContext(); const persistMember = (next: typeof member) => { if (!next) { return; } setMember(next); try { localStorage.setItem('member', JSON.stringify(next)); document.cookie = `member=${encodeURIComponent(JSON.stringify(next))}; path=/; max-age=${60 * 60 * 24 * 30}`; } catch { // ignore } }; const [bannerFile, setBannerFile] = useState(null); const [bannerPreview, setBannerPreview] = useState(profile.bannerUrl); const [bannerRemoved, setBannerRemoved] = useState(false); const [thumbFile, setThumbFile] = useState(null); const [thumbPreview, setThumbPreview] = useState(profile.thumb); const [name, setName] = useState(profile.name ?? ''); const [intro, setIntro] = useState(profile.intro ?? ''); const [submitting, setSubmitting] = useState(false); const [error, setError] = useState(null); const bannerInputRef = useRef(null); const thumbInputRef = useRef(null); const handleBannerSelect = (files: FileList|null) => { const file = files?.[0]; if (!file || !file.type.startsWith('image/')) { return; } setBannerFile(file); setBannerRemoved(false); const reader = new FileReader(); reader.onloadend = () => setBannerPreview(reader.result as string); reader.readAsDataURL(file); }; const handleBannerRemove = () => { setBannerFile(null); setBannerPreview(null); setBannerRemoved(true); }; const handleThumbSelect = (files: FileList|null) => { const file = files?.[0]; if (!file || !file.type.startsWith('image/')) { return; } setThumbFile(file); const reader = new FileReader(); reader.onloadend = () => setThumbPreview(reader.result as string); reader.readAsDataURL(file); }; const handleSubmit = async () => { if (!member || submitting) { return; } setSubmitting(true); setError(null); try { const nameChanged = name.trim() !== (profile.name ?? ''); const introChanged = intro !== (profile.intro ?? ''); if (bannerFile) { const form = new FormData(); form.append('banner', bannerFile); const res = await fetchApi<{ bannerUrl: string }>('/api/mypage/banner', { method: 'POST', body: form, silent: true }); if (!res.success) { throw new Error(res.message ?? '배너 업로드 실패'); } } else if (bannerRemoved && profile.bannerUrl) { const res = await fetchApi('/api/mypage/banner', { method: 'DELETE', silent: true }); if (!res.success) { throw new Error(res.message ?? '배너 삭제 실패'); } } if (thumbFile) { const form = new FormData(); form.append('thumb', thumbFile); const res = await fetchApi<{ thumbUrl: string }>('/api/mypage/thumb', { method: 'POST', body: form, silent: true }); if (!res.success) { throw new Error(res.message ?? '프로필 사진 업로드 실패'); } if (member && res.data?.thumbUrl !== undefined) { persistMember({ ...member, thumb: res.data.thumbUrl }); } } if (nameChanged) { const res = await fetchApi('/api/mypage/name', { method: 'POST', body: { Name: name.trim() }, silent: true }); if (!res.success) { throw new Error(res.message ?? '별명 변경 실패'); } if (member) { persistMember({ ...member, name: name.trim() }); } } if (introChanged) { const res = await fetchApi('/api/mypage/intro', { method: 'POST', body: { Intro: intro }, silent: true }); if (!res.success) { throw new Error(res.message ?? '자기소개 변경 실패'); } if (member) { persistMember({ ...member, intro }); } } onOpenChange(false); router.refresh(); } catch (err) { setError(err instanceof Error ? err.message : '저장 실패'); } finally { setSubmitting(false); } }; return ( 프로필 편집
{bannerPreview ? ( 배너 미리보기 ) : (
)}
{bannerPreview && ( )}
handleBannerSelect(e.target.files)} />
{thumbPreview ? ( 프로필 사진 미리보기 ) : ( )} handleThumbSelect(e.target.files)} />